Introduction

03A-make_network

Make network

Randomize networks

For record, it took 2603 seconds ~= 40 mins to generate 10000 randomized networks for all 13 communities.

It took ~50 seconds to randomize 1000 times for each of the communities. So total of 641 seconds needed.

The randomized networks are saved in data/output/network_randomized.Rdata which contains a two-layer R list net_randomized_list in which the first layer has the 13 communities and the second layer has 1000 randomized networks.

Example of randomized network matrix

03B-network_measure

Detect motifs in networks

  • networks_motif: data.frame
  • networks_motif_randomized: data.frame for all randomized networks motif counts

Empirical network motifs. 13 communities x 7 motifs = 91 rows

Rows: 91 Columns: 4
── Column specification ────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): Community
dbl (3): Motif, Count, Fraction

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Shuffled network motifs. 13 communities x 7 motifs x 1000 bootstraps = 91000 rows

Competitive hierarchy

See Higgins2017 for the hierarchy score calculation. Briefly, the hierarchy score is based on the relative abundance of each pair and it ranges from 0.5 (pure non-hierarchy with all pairs coexist at 50%:50%) to 1 (pure hierarchy with all pairs being exclusion and forming a transitive network).

The hierarchy score of each communities is compared to a set of 1000 randomized networks which keeps the same relative abundances of each pairs but shuffled.

Diagonal analysis

For record, it took 1655 seconds ~= 26 minutes to compute the diagonal measures for 13 communities X 10000 randomization, merge them into one single data frame.

data/output/networks_diag

data/output/networks_diag_randomized

For a network matrix \(m_{ij}\), the fraction of coexistence as a fucntion of distance to diagonal is calculated as the

\[\frac{}{\lvert i-j \lvert}\]

networks_diag_randomized has four columns

Randomization: the number of randomization

Rows: 37 Columns: 3
── Column specification ────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): Community
dbl (2): DistanceToDiagonal, CountCoexistence

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 34840 Columns: 4
── Column specification ────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): Community
dbl (3): Randomization, DistanceToDiagonal, CountCoexistence

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Node degree in coexistence-only network

Rows: 68 Columns: 3
── Column specification ──────────────────────────────────────────────────────
Delimiter: ","
chr (1): Community
dbl (2): Degree, Isolate

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 68000 Columns: 4
── Column specification ──────────────────────────────────────────────────────
Delimiter: ","
dbl (4): Community, Replicate, Degree, Isolate

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Network component of coexistence-only networks

Rows: 13 Columns: 2
── Column specification ──────────────────────────────────────────────────────
Delimiter: ","
chr (1): Community
dbl (1): Component

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 13000 Columns: 3
── Column specification ──────────────────────────────────────────────────────
Delimiter: ","
dbl (3): Community, Replicate, Component

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Summary

isolates <- read_csv(here::here("data/output/isolates.csv"))
Rows: 100 Columns: 62
── Column specification ────────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (8): Assembly, ExpID, Community, Family, Genus, Sequence, PreferredCS, SecretedCS
dbl (52): ID, Isolate, GenusScore, ColonyCount, DilutionFactor, Epsilon, Win, Lose, Draw...
lgl  (2): Fermenter, GramPositive

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
pairs <- read_csv(here::here("data/output/pairs.csv"))
Rows: 248 Columns: 29
── Column specification ────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (14): Assembly, Community, InteractionType, InteractionTypeFiner, ExpID1, Family1, G...
dbl (10): Isolate1, Isolate2, From, To, ID1, GenusScore1, ID2, GenusScore2, SeqDifferenc...
lgl  (5): Fermenter1, GramPositive1, Fermenter2, GramPositive2, Isolate1Dominant

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
communities <- read_csv(here::here("data/output/communities.csv"))
Rows: 17 Columns: 4
── Column specification ────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (1): Community
dbl (3): CommunitySize, CommunityPairSize, CommunitiyMotifSize

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
load(here::here("data/output/network_community.Rdata"))

Convert the graph file into txt

So that the graph is readable in python

Error: object 'f' not found

Plot network in matrix

Upper half matrices

Plot network in graph

There are some functions to play with

Combine matrix and network plot

$C1R2
[1] NA

$C1R4
[1] NA

$C1R6
[1] NA

$C1R7
[1] NA

$C2R6
[1] NA

$C2R8
[1] NA

$C4R1
[1] NA

$C7R1
[1] NA

$C8R4
[1] NA

$C10R2
[1] NA

$C11R1
[1] NA

$C11R2
[1] NA

$C11R5
[1] NA

LS0tCnRpdGxlOiAiQW5hbHlzaXMgb24gdGhlIGVtcGlyaWNhbCBpbnZhc2lvbiBuZXR3b3JrcyIKYXV0aG9yOiAiQ2hhbmctWXUgQ2hhbmciCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6ICAKICAgIHRvYzogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGUgPSBGfQprbml0cjo6b3B0c19jaHVuayRzZXQoY2FjaGUgPSBGQUxTRSwgZWNobyA9IEZBTFNFKQoKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KGlncmFwaCkKbGlicmFyeSh0aWR5Z3JhcGgpCmxpYnJhcnkoZ2dyYXBoKQpzb3VyY2UoaGVyZTo6aGVyZSgicGxvdHRpbmdfc2NyaXB0cy9uZXR3b3JrX2Z1bmN0aW9ucy5SIikpCnJ1bl9zY3JpcHRzIDwtIEYKY29tbXVuaXRpZXMgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS9vdXRwdXQvY29tbXVuaXRpZXMuY3N2IikpCmBgYAoKIyBJbnRyb2R1Y3Rpb24KCi0gVGhlIFIgc2NyaXB0cyAoc291cmNlZCBpbiB0aGlzIFJtZCkgY2FuIGJlIHJ1biBleHRlcm5hbGx5IHRvIFJzdHVkaW8uCi0gVGhlIFIgc2NyaXB0cyBhcmUgb25seSBmb3Igc2F2aW5nIFIgZnVuY3Rpb25zLCBwcm9jZXNzaW5nIHJhdyBhbmQgdGVtcG9yYXJ5IGRhdGEuCi0gQWxsIHZpc3VhbGl6YXRpb24gY29kZXMgYXJlIGluIHRoaXMgUm1kIGZpbGUuCgojIDAzQS1tYWtlX25ldHdvcmsKCi0gTWFrZSBjb21tdW5pdHkgbmV0d29yayBmcm9tIGBkYXRhL291dHB1dC9wYWlycy5jc3ZgLgoKLSBQbG90IG5ldHdvcmtzIGFuZCBtYXRyaWNlcwoKIyMgTWFrZSBuZXR3b3JrCgpgYGB7cn0KaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wM0EtbWFrZV9uZXR3b3JrLTAxLW1ha2VfcGFpcndpc2VfbmV0d29yay5SIikKYGBgCgoKYGBge3IgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTh9CmxvYWQoaGVyZTo6aGVyZSgiZGF0YS9vdXRwdXQvbmV0d29ya19jb21tdW5pdHkuUmRhdGEiKSkKcF9uZXRfbGlzdCA8LSBsYXBwbHkobmV0X2xpc3QsIHBsb3RfY29tcGV0aXRpdmVfbmV0d29yaykgJT4lIHN1cHByZXNzV2FybmluZ3MoKQpwbG90X2dyaWQocGxvdGxpc3QgPSBwX25ldF9saXN0LCBuY29sID0gNCkKYGBgCgoKIyMgUmFuZG9taXplIG5ldHdvcmtzCgpgYGB7cn0KaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wM0EtbWFrZV9uZXR3b3JrLTAzLXJhbmRvbWl6ZV9uZXR3b3JrLlIiKQpgYGAKCkZvciByZWNvcmQsIGl0IHRvb2sgMjYwMyBzZWNvbmRzIH49IDQwIG1pbnMgdG8gZ2VuZXJhdGUgMTAwMDAgcmFuZG9taXplZCBuZXR3b3JrcyBmb3IgYWxsIDEzIGNvbW11bml0aWVzLiAKCkl0IHRvb2sgfjUwIHNlY29uZHMgdG8gcmFuZG9taXplIDEwMDAgdGltZXMgZm9yIGVhY2ggb2YgdGhlIGNvbW11bml0aWVzLiBTbyB0b3RhbCBvZiA2NDEgc2Vjb25kcyBuZWVkZWQuCgpUaGUgcmFuZG9taXplZCBuZXR3b3JrcyBhcmUgc2F2ZWQgaW4gYGRhdGEvb3V0cHV0L25ldHdvcmtfcmFuZG9taXplZC5SZGF0YWAgd2hpY2ggY29udGFpbnMgYSB0d28tbGF5ZXIgUiBsaXN0IGBuZXRfcmFuZG9taXplZF9saXN0YCBpbiB3aGljaCB0aGUgZmlyc3QgbGF5ZXIgaGFzIHRoZSAxMyBjb21tdW5pdGllcyBhbmQgdGhlIHNlY29uZCBsYXllciBoYXMgMTAwMCByYW5kb21pemVkIG5ldHdvcmtzLgoKRXhhbXBsZSBvZiByYW5kb21pemVkIG5ldHdvcmsgbWF0cml4CmBgYHtyIGZpZy53aWR0aCA9IDMsIGZpZy5oZWlnaHQgPSAzfQpsb2FkKGhlcmU6OmhlcmUoImRhdGEvb3V0cHV0L25ldHdvcmtfcmFuZG9taXplZC5SZGF0YSIpKQpuZXRfcmFuZG9taXplZF9saXN0JEMxMVIyW1sxXV0gJT4lIHBsb3RfYWRqYWNlbnRfbWF0cml4KCkKYGBgCgoKIyAwM0ItbmV0d29ya19tZWFzdXJlCgojIyBEZXRlY3QgbW90aWZzIGluIG5ldHdvcmtzCgpgYGB7ciBldmFsID0gRn0KIyBUaGlzIG1heSB0YWtlIH41IG1pbnV0ZXMgZm9yIDEwMDAwIGJvb3RzdHJhcHBpbmcKaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wM0ItbmV0d29ya19tZWFzdXJlLTAxLWRldGVjdF9tb3RpZi5SIikKYGBgCgotIGBuZXR3b3Jrc19tb3RpZmA6IGRhdGEuZnJhbWUKLSBgbmV0d29ya3NfbW90aWZfcmFuZG9taXplZGA6IGRhdGEuZnJhbWUgZm9yIGFsbCByYW5kb21pemVkIG5ldHdvcmtzIG1vdGlmIGNvdW50cwoKRW1waXJpY2FsIG5ldHdvcmsgbW90aWZzLiAxMyBjb21tdW5pdGllcyB4IDcgbW90aWZzID0gOTEgcm93cwoKYGBge3J9Cm5ldHdvcmtzX21vdGlmIDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvb3V0cHV0L25ldHdvcmtzX21vdGlmLmNzdiIpKQpuZXR3b3Jrc19tb3RpZgpgYGAKClNodWZmbGVkIG5ldHdvcmsgbW90aWZzLiAxMyBjb21tdW5pdGllcyB4IDcgbW90aWZzIHggMTAwMCBib290c3RyYXBzID0gOTEwMDAgcm93cwoKYGBge3J9Cm5ldHdvcmtzX21vdGlmX3JhbmRvbWl6ZWQgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS9vdXRwdXQvbmV0d29ya3NfbW90aWZfcmFuZG9taXplZC5jc3YiKSkKbmV0d29ya3NfbW90aWZfcmFuZG9taXplZApgYGAKCiMjIENvbXBldGl0aXZlIGhpZXJhcmNoeQoKYGBge3J9CmlmIChydW5fc2NyaXB0cykgc291cmNlKCJzY3JpcHQvMDNCLW5ldHdvcmtfbWVhc3VyZS0wMi1jb21wZXRpdGl2ZV9oaWVyYXJjaHkuUiIpCmBgYAoKU2VlIEhpZ2dpbnMyMDE3IGZvciB0aGUgaGllcmFyY2h5IHNjb3JlIGNhbGN1bGF0aW9uLiBCcmllZmx5LCB0aGUgaGllcmFyY2h5IHNjb3JlIGlzIGJhc2VkIG9uIHRoZSByZWxhdGl2ZSBhYnVuZGFuY2Ugb2YgZWFjaCBwYWlyIGFuZCBpdCByYW5nZXMgZnJvbSAwLjUgKHB1cmUgbm9uLWhpZXJhcmNoeSB3aXRoIGFsbCBwYWlycyBjb2V4aXN0IGF0IDUwJTo1MCUpIHRvIDEgKHB1cmUgaGllcmFyY2h5IHdpdGggYWxsIHBhaXJzIGJlaW5nIGV4Y2x1c2lvbiBhbmQgZm9ybWluZyBhIHRyYW5zaXRpdmUgbmV0d29yaykuCgpUaGUgaGllcmFyY2h5IHNjb3JlIG9mIGVhY2ggY29tbXVuaXRpZXMgaXMgY29tcGFyZWQgdG8gYSBzZXQgb2YgMTAwMCByYW5kb21pemVkIG5ldHdvcmtzIHdoaWNoIGtlZXBzIHRoZSBzYW1lIHJlbGF0aXZlIGFidW5kYW5jZXMgb2YgZWFjaCBwYWlycyBidXQgc2h1ZmZsZWQuIAoKCiMjIERpYWdvbmFsIGFuYWx5c2lzCgpgYGB7cn0KIyBJdCB0YWtlcyAyNiBtaW51dGVzIHRvIHJ1biB0aGlzIHNjcmlwdCBmb3IgMTAwMDAgYm9vdHN0cmFwcwppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAzQi1uZXR3b3JrX21lYXN1cmUtMDMtZGlzdGFuY2VfdG9fZGlhZ29uYWwuUiIpCmBgYAoKRm9yIHJlY29yZCwgaXQgdG9vayAxNjU1IHNlY29uZHMgfj0gMjYgbWludXRlcyB0byBjb21wdXRlIHRoZSBkaWFnb25hbCBtZWFzdXJlcyBmb3IgMTMgY29tbXVuaXRpZXMgWCAxMDAwMCByYW5kb21pemF0aW9uLCBtZXJnZSB0aGVtIGludG8gb25lIHNpbmdsZSBkYXRhIGZyYW1lLgoKYGRhdGEvb3V0cHV0L25ldHdvcmtzX2RpYWdgCgpgZGF0YS9vdXRwdXQvbmV0d29ya3NfZGlhZ19yYW5kb21pemVkYAoKRm9yIGEgbmV0d29yayBtYXRyaXggJG1fe2lqfSQsIHRoZSBmcmFjdGlvbiBvZiBjb2V4aXN0ZW5jZSBhcyBhIGZ1Y250aW9uIG9mIGRpc3RhbmNlIHRvIGRpYWdvbmFsIGlzIGNhbGN1bGF0ZWQgYXMgdGhlCgokJFxmcmFje317XGx2ZXJ0IGktaiBcbHZlcnR9JCQKIApgbmV0d29ya3NfZGlhZ19yYW5kb21pemVkYCBoYXMgZm91ciBjb2x1bW5zCgpgUmFuZG9taXphdGlvbmA6IHRoZSBudW1iZXIgb2YgcmFuZG9taXphdGlvbiAKCmBgYHtyfQpuZXR3b3Jrc19kaWFnIDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvb3V0cHV0L25ldHdvcmtzX2RpYWcuY3N2IikpCm5ldHdvcmtzX2RpYWdfcmFuZG9taXplZApgYGAKCmBgYHtyfQpuZXR3b3Jrc19kaWFnX3JhbmRvbWl6ZWQgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS9vdXRwdXQvbmV0d29ya3NfZGlhZ19yYW5kb21pemVkLmNzdiIpKQpuZXR3b3Jrc19kaWFnX3JhbmRvbWl6ZWQKYGBgCgojIyBOb2RlIGRlZ3JlZSBpbiBjb2V4aXN0ZW5jZS1vbmx5IG5ldHdvcmsKCmBgYHtyfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAzQi1uZXR3b3JrX21lYXN1cmUtMDQtbm9kZV9kZWdyZWUuUiIpCmBgYAoKCmBgYHtyfQpuZXR3b3Jrc19kZWdyZWUgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS9vdXRwdXQvbmV0d29ya3NfZGVncmVlLmNzdiIpKQpuZXR3b3Jrc19kZWdyZWUKYGBgCgpgYGB7cn0KbmV0d29ya3NfZGVncmVlX3JhbmRvbWl6ZWQgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS9vdXRwdXQvbmV0d29ya3NfZGVncmVlX3JhbmRvbWl6ZWQuY3N2IikpCm5ldHdvcmtzX2RlZ3JlZV9yYW5kb21pemVkCmBgYAoKCgoKIyMgTmV0d29yayBjb21wb25lbnQgb2YgY29leGlzdGVuY2Utb25seSBuZXR3b3JrcwoKYGBge3J9CmlmIChydW5fc2NyaXB0cykgc291cmNlKCJzY3JpcHQvMDNCLW5ldHdvcmtfbWVhc3VyZS0wNS1jb21wb25lbnRfY291bnQuUiIpCmBgYAoKCmBgYHtyfQpuZXR3b3Jrc19jb21wb25lbnQgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS9vdXRwdXQvbmV0d29ya3NfY29tcG9uZW50LmNzdiIpKQpuZXR3b3Jrc19jb21wb25lbnQKYGBgCgoKYGBge3J9Cm5ldHdvcmtzX2NvbXBvbmVudF9yYW5kb21pemVkIDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvb3V0cHV0L25ldHdvcmtzX2NvbXBvbmVudF9yYW5kb21pemVkLmNzdiIpKQpuZXR3b3Jrc19jb21wb25lbnRfcmFuZG9taXplZAoKYGBgCgoKCiMgU3VtbWFyeQoKCi0gYGlzb2xhdGVzYDogNjggaXNvbGF0ZXMKLSBgcGFpcnNgOiAxODYgcGFpcnMKLSBgY29tbXVuaXRpZXNgOiBtZXRhZGF0YSBvZiAxMyBjb21tdW5pdGllcwotIGBuZXR3b3JrX2NvbW11bml0eS5SZGF0YWAgc2F2ZXMgb25lIFIgbGlzdHMuIGBuZXRfbGlzdGAgIGhhcyAxMyBgdGJsX2dyYXBoYCBvYmplY3RzLiB0aGF0IGRlc2NyaWJlcyB0aGUgY29tcGV0aXRpdmUgbmV0d29ya3Mgb2YgbXkgY29tbXVuaXRpZXMsIHdoZXJlIGBwX25ldF9saXN0YCBoYXMgMTMgcGljdHVyZXMuCgpgYGB7ciBlY2hvID0gVH0KaXNvbGF0ZXMgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS9vdXRwdXQvaXNvbGF0ZXMuY3N2IikpCnBhaXJzIDwtIHJlYWRfY3N2KGhlcmU6OmhlcmUoImRhdGEvb3V0cHV0L3BhaXJzLmNzdiIpKQpjb21tdW5pdGllcyA8LSByZWFkX2NzdihoZXJlOjpoZXJlKCJkYXRhL291dHB1dC9jb21tdW5pdGllcy5jc3YiKSkKbG9hZChoZXJlOjpoZXJlKCJkYXRhL291dHB1dC9uZXR3b3JrX2NvbW11bml0eS5SZGF0YSIpKQpgYGAKCgojIyBDb252ZXJ0IHRoZSBncmFwaCBmaWxlIGludG8gdHh0IAoKU28gdGhhdCB0aGUgZ3JhcGggaXMgcmVhZGFibGUgaW4gcHl0aG9uCgpgYGB7cn0KbG9hZChoZXJlOjpoZXJlKCJkYXRhL291dHB1dC9uZXR3b3JrX2NvbW11bml0eS5SZGF0YSIpKQpsb2FkKGhlcmU6OmhlcmUoImRhdGEvb3V0cHV0L21vdGlmX2xpc3QuUmRhdGEiKSkKCiMgT25seSB1c2UgdGhvc2UgdGhhdCBhcmUgCmxpYnJhcnkoaWdyYXBoKQpmb3IgKGkgaW4gMTpsZW5ndGgobmV0X2xpc3QpKSB7CiAgICB3cml0ZV9ncmFwaChuZXRfbGlzdFtbaV1dLCBoZXJlOjpoZXJlKHBhc3RlMCgiZGF0YS90ZW1wL25ldHdvcmtzLyIsIG5hbWVzKG5ldF9saXN0KVtpXSwgIi50eHQiKSkpCn0KZm9yIChpIGluIDE6bGVuZ3RoKG1vdGlmX2xpc3QpKSB7CiAgICB3cml0ZV9ncmFwaChtb3RpZl9saXN0W1tpXV0sIGhlcmU6OmhlcmUocGFzdGUwKCJkYXRhL3RlbXAvbmV0d29ya3MvbW90aWYiLCBpLCAiLnR4dCIpKSkKfQoKCndyaXRlX2dyYXBoKG5ldF9saXN0W1tpXV0sIGhlcmU6OmhlcmUocGFzdGUwKCJkYXRhL3RlbXAvbmV0d29ya3MvIiwgbmFtZXMobmV0X2xpc3QpW2ldLCAiLnR4dCIpKSkKd3JpdGVfZ3JhcGgobW90aWZfbGlzdFtbaV1dLCBoZXJlOjpoZXJlKHBhc3RlMCgiZGF0YS90ZW1wL25ldHdvcmtzLyIsIG5hbWVzKG5ldF9saXN0KVtpXSwgIi50eHQiKSkpCgpgYGAKCgoKIyMgUGxvdCBuZXR3b3JrIGluIG1hdHJpeAoKVXBwZXIgaGFsZiBtYXRyaWNlcwoKYGBge3IgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9OH0KcF9uZXRfbWF0cml4X2xpc3QgPC0gbGFwcGx5KG5ldF9saXN0LCBmdW5jdGlvbih4KSBwbG90X2FkamFjZW50X21hdHJpeCh4KSkgJT4lIHNldE5hbWVzKGNvbW11bml0aWVzJENvbW11bml0eSkKcF9uZXRfbWF0cml4X2xpc3QgPC0gcF9uZXRfbWF0cml4X2xpc3Rbb3JkZXIoY29tbXVuaXRpZXMkQ29tbXVuaXR5U2l6ZSwgZGVjcmVhc2luZyA9IFQpXQpwbG90X2dyaWQocGxvdGxpc3QgPSBwX25ldF9tYXRyaXhfbGlzdCwgbGFiZWxzID0gTEVUVEVSU1syOjE0XSwgbmNvbCA9IDMsIGhqdXN0ID0gMSkKYGBgCgojIyBQbG90IG5ldHdvcmsgaW4gZ3JhcGgKClRoZXJlIGFyZSBzb21lIGZ1bmN0aW9ucyB0byBwbGF5IHdpdGggCmBgYHtyLCBmaWcud2lkdGg9NSwgZmlnLmhlaWdodD04fQpwX25ldF9saXN0IDwtIHBfbmV0X2xpc3Rbb3JkZXIoY29tbXVuaXRpZXMkQ29tbXVuaXR5U2l6ZSxkZWNyZWFzaW5nID0gVCldCnBsb3RfZ3JpZChwbG90bGlzdCA9IHBfbmV0X2xpc3QsIGxhYmVscyA9IExFVFRFUlNbMjoxNF0sIG5jb2wgPSAzLCBoanVzdCA9IC0xKQpgYGAKCiMjIENvbWJpbmUgbWF0cml4IGFuZCBuZXR3b3JrIHBsb3QKCmBgYHtyfQpwX2xpc3QgPC0gcmVwKGxpc3QoTkEpLCBsZW5ndGgobmV0X2xpc3QpKQpuYW1lcyhwX2xpc3QpIDwtIGNvbW11bml0aWVzJENvbW11bml0eQoKZm9yIChpIGluIDE6bGVuZ3RoKG5ldF9saXN0KSkgewogIHBfbGlzdFtbaV1dIDwtIGdnZHJhdyhwX25ldF9tYXRyaXhfbGlzdFtbaV1dKSArCiAgICBkcmF3X3Bsb3QocGxvdCA9IHBfbmV0X2xpc3RbW2ldXSwgeCA9IDAsIHkgPSAwLCB3aWR0aCA9IDAuNDUsIGhlaWdodCA9IDAuNSkKfQpgYGAKCgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTE2fQpwIDwtIHBsb3RfZ3JpZChwbG90bGlzdCA9IHBfbGlzdCwgbmNvbCA9IDMsIGhqdXN0ID0gLTEsIHZqdXN0ID0gMSkKZ2dzYXZlKCJmaWd1cmUvMDMtbmV0d29ya3MucG5nIiwgd2lkdGggPSAyMCwgaGVpZ2h0ID0gMzIpCnAKYGBgCgoKCg==